package com.maybach.core.ao.impl;


import com.maybach.core.ao.FlowApplyAO;
import com.maybach.core.form.flow.FlowActForm;
import com.maybach.core.form.flow.TaskActForm;
import com.maybach.core.security.AdminUserUtil;
import com.maybach.util.AssertUtil;
import com.maybach.util.query.support.BaseCriteria;
import com.maybach.util.query.support.PageResult;
import com.maybach.workflow.common.api.IFlowEngine;
import com.maybach.workflow.common.api.enums.FlowActTypeEnum;
import com.maybach.workflow.common.api.enums.FlowStateEnum;
import com.maybach.workflow.common.api.exception.FlowException;
import com.maybach.workflow.common.ext.ApplyIndex;
import com.maybach.workflow.common.ext.FlowActInfo;
import com.maybach.workflow.common.ext.FlowTaskInfo;
import com.maybach.workflow.common.ext.TaskActInfo;
import com.maybach.workflow.common.model.*;
import com.maybach.workflow.common.query.FlowApplyIndexQuery;
import com.maybach.workflow.common.query.FlowApplyQuery;
import com.maybach.workflow.common.query.FlowTaskHisQuery;
import com.maybach.workflow.common.query.FlowTaskQuery;
import com.maybach.workflow.core.manager.*;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by houenxun on 16/1/13.
 */
@Component
public class FlowApplyAOImpl implements FlowApplyAO {
    @Autowired
    FlowManager flowManager;
    @Autowired
    FlowTaskManager flowTaskManager;
    @Autowired
    FlowApplyManager flowApplyManager;
    @Autowired
    FlowTaskHisManager flowTaskHisManager;
    @Autowired
    FlowApplyIndexManager flowApplyIndexManager;

    @Override
    public void executeTask(TaskActForm taskActForm) {
        // 数据转换
        TaskActInfo taskActInfo = new TaskActInfo();
        taskActInfo.setTaskId(taskActForm.getTaskId());
        taskActInfo.setActType(taskActForm.getActType());
        taskActInfo.setMemo(taskActForm.getMemo());
        FlowTaskDO taskDO = flowTaskManager.selectByPrimaryKey(taskActForm.getTaskId());

        // 执行任务
        flowEngine.executeTask(taskActInfo);

        // 同步状态到apply
        FlowDO flowDO = flowManager.selectByPrimaryKey(taskDO.getFlowId());
        synFlowApplyState(flowDO);

    }

    @Override
    public void operaterFlow(FlowActForm flowActForm) {
        FlowActInfo flowActInfo = new FlowActInfo();
        flowActInfo.setFlowId(flowActForm.getFlowId());
        flowActInfo.setMemo(flowActForm.getMemo());
        flowActInfo.setActType(flowActForm.getActType());
        flowEngine.operaterFlow(flowActInfo);
        FlowDO flowDO = flowManager.selectByPrimaryKey(flowActForm.getFlowId());
        synFlowApplyState(flowDO);
    }


    //@Override
    public FlowApplyDO getApplyByFlowId(Long flowId) {
        FlowDO flowDO = flowManager.selectByPrimaryKey(flowId);
        AssertUtil.notNull(flowDO, "flowDO by flowId=" + flowId);
        return this.getApplyById(flowDO.getBizId());
    }

    @Override
    public FlowApplyDO getApplyByTaskId(Long taskId) {
        FlowTaskDO taskDO = flowTaskManager.selectByPrimaryKey(taskId);
        if (null == taskDO) {
            FlowTaskHisQuery query = new FlowTaskHisQuery();
            query.or().andTaskIdEqualTo(taskId);
            List<FlowTaskHisDO> his = flowTaskHisManager.selectByQuery(query);
            AssertUtil.notNull(his.size() == 0, "his query by taskId=" + taskId + ", size=" + his.size());
            return this.getApplyByFlowId(his.get(0).getFlowId());
        }
        return this.getApplyByFlowId(taskDO.getFlowId());
    }

    @Autowired
    IFlowEngine flowEngine;

    @Override
    public Long createApply(FlowApplyDO apply) {

        if (null == apply.getState()) {
            apply.setState(FlowStateEnum.init.getStatus());
        }
        if (null == apply.getCreator()) {
            apply.setCreator(AdminUserUtil.getUser().getAdminId());
        }
        flowApplyManager.insertSelective(apply);
        Long applyId = apply.getId();
        Object content = apply.getContentObject();

        createApplyIndex(applyId, content);

        if (content instanceof FlowActInfo) {
            ((FlowActInfo) content).setFlowBizId(applyId);
            ((FlowActInfo) content).setFlowBizType(apply.getFlowBizType());
            flowEngine.startFlow((FlowActInfo) content);
        } else {
            flowEngine.startFlow(applyId, apply.getFlowBizType());

        }

        return applyId;
    }

    private void clearApplyIndex(Long applyId) {
        AssertUtil.notNull(applyId, "applyId");
        FlowApplyIndexQuery query = new FlowApplyIndexQuery();
        FlowApplyIndexQuery.Criteria criteria = query.or();
        criteria.andApplyIdEqualTo(applyId);
        flowApplyIndexManager.deleteByQuery(query);
    }


    /**
     * 创建索引
     *
     * @param applyId
     * @param content
     */
    private void createApplyIndex(Long applyId, Object content) {
        for (Field field : content.getClass().getDeclaredFields()) {
            ApplyIndex indexAnnotation = field.getAnnotation(ApplyIndex.class);
            if (null != indexAnnotation) {
                FlowApplyIndexDO flowApplyIndexDO = new FlowApplyIndexDO();
                flowApplyIndexDO.setApplyId(applyId);
                flowApplyIndexDO.setName(StringUtils.isNotBlank(indexAnnotation.indexName()) ? indexAnnotation.indexName() : field.getName());
                field.setAccessible(true);
                try {
                    Object obj = field.get(content);
                    flowApplyIndexDO.setValue(obj != null ? obj.toString() : null);
                } catch (Exception e) {

                }
                flowApplyIndexManager.insertSelective(flowApplyIndexDO);
            }
        }
    }

    @Override
    public void updateApply(FlowApplyDO applyDO) {
        flowApplyManager.updateByPrimaryKeySelective(applyDO);
        clearApplyIndex(applyDO.getId());
        Object content = applyDO.getContentObject();
        createApplyIndex(applyDO.getId(), content);
    }

    public FlowApplyDO getApplyById(Long id) {
        return flowApplyManager.selectByPrimaryKey(id);
    }


    @Override
    public Long reApplyFlow(FlowApplyDO applyDO, Long taskId) {
        AssertUtil.notNull(applyDO.getId(), "applyDO.getApplyId()");
        taskId = this.getTaskId(taskId, applyDO);
        applyDO.setState(FlowStateEnum.init.getStatus());
        flowApplyManager.updateByPrimaryKeySelective(applyDO);
        clearApplyIndex(applyDO.getId());
        Object content = applyDO.getContentObject();
        createApplyIndex(applyDO.getId(), content);


        if (content instanceof FlowActInfo) {
            TaskActInfo actInfo = new TaskActInfo();
            actInfo.setTaskId(taskId);
            actInfo.setActType(FlowActTypeEnum.pass.name());
            actInfo.setReasonDesc(((FlowActInfo) content).getReasonDesc());
            actInfo.setReasonCode(((FlowActInfo) content).getReasonCode());
            actInfo.setMemo(((FlowActInfo) content).getReasonCode());
            flowEngine.executeTask(actInfo);
        } else {
            flowEngine.executeTask(taskId);

        }
        return applyDO.getId();
    }

    /**
     * 获取任务id，如果外界没有传入 自动获取
     *
     * @param taskId
     * @param applyDO
     * @return
     */
    Long getTaskId(Long taskId, FlowApplyDO applyDO) {
        if (null != taskId) {
            return taskId;
        }
        FlowTaskQuery quer = new FlowTaskQuery();
        FlowTaskQuery.Criteria criteria = quer.or();
        criteria.andBizIdEqualTo(applyDO.getId());
        criteria.andBizTypeEqualTo(applyDO.getFlowBizType());
        List<FlowTaskDO> flowTaskDOs = flowTaskManager.selectByQuery(quer);
        if (flowTaskDOs.size() == 1) {
            return flowTaskDOs.get(0).getId();
        }
        throw new FlowException("没有可以执行的任务", null);

    }

    @Override
    public PageResult<FlowApplyDO> queryFlowApply(FlowApplyQuery query, List<FlowApplyIndexQuery> list) {
        if (null == query) {
            query = new FlowApplyQuery();
            query.setPageSize(query.DEFAULT_PAGE_SIZE);
            query.setPageNo(query.DEFAULT_PAGE);
        } else {
            if (null == query.getPageNo()) {
                query.setPageNo(query.DEFAULT_PAGE);
            }
            if (null == query.getPageSize()) {
                query.setPageSize(query.DEFAULT_PAGE_SIZE);
            }
        }
        // 1. 根据index过滤查询 符合条件的 applyId
        List<Long> applyIdList = null;
        if (CollectionUtils.isNotEmpty(list)) {
            for (final FlowApplyIndexQuery indexQuery : list) {
                if (null != applyIdList) {
                    if (CollectionUtils.isEmpty(indexQuery.getOredCriteria())) {
                        indexQuery.or().andApplyIdIn(applyIdList);
                    } else {
                        for (BaseCriteria criteria : indexQuery.getOredCriteria()) {
                            ((FlowApplyIndexQuery.Criteria) criteria).andApplyIdIn(applyIdList);
                        }
                    }
                }
                List<FlowApplyIndexDO> applyIndexDOList = flowApplyIndexManager.selectByQuery(indexQuery);
                applyIdList = new ArrayList<Long>();
                for(FlowApplyIndexDO applyIndexDO : applyIndexDOList){
                    applyIdList.add(applyIndexDO.getApplyId());
                }
                if (applyIdList.isEmpty()) {
                    break;
                }
            }
        }

        // 2. 将符合条件的 applyId作为过滤条件 联通原有的查询条件一起进行查询
        if (null != applyIdList && applyIdList.size() == 0) { // 经过上一步过滤已经无数据
            PageResult<FlowApplyDO> result = new PageResult<FlowApplyDO>();
            result.setResult(new ArrayList<FlowApplyDO>());
            result.setTotalCount(0);
            return result;
        } else {
            if (null != applyIdList) { // 把applyIdList作为进一步的过滤条件
                if (CollectionUtils.isNotEmpty(query.getOredCriteria())) {
                    for (BaseCriteria criteria : query.getOredCriteria()) {
                        ((FlowApplyQuery.Criteria) criteria).andIdIn(applyIdList);
                    }
                } else {
                    query.or().andIdIn(applyIdList);
                }
            }
            return flowApplyManager.selectByQueryWithPage(query);
        }

    }

    @Override
    public List<FlowTaskInfo> getTasksByApplyId(Long applyId, boolean filter) {
        FlowApplyDO applyDO = this.flowApplyManager.selectByPrimaryKey(applyId);
        if (null == applyDO) {
            return null;
        }

        return this.getTasksByApplyId(applyDO, filter);
    }

    @Override
    public List<FlowTaskInfo> getTasksByApplyId(FlowApplyDO applyDO, boolean filter) {
        return flowEngine.getTasks(applyDO.getFlowBizType(), applyDO.getId(), filter);
    }


    /**
     * 同步flowApply的状态使其和流程保持一致
     *
     * @param flowDO
     */
    private void synFlowApplyState(FlowDO flowDO) {

        FlowApplyDO flowApplyDO = flowApplyManager.selectByPrimaryKey(flowDO.getBizId());
        if (!flowApplyDO.getState().equals(flowDO.getFlowState())) {
            flowApplyDO.setState(flowDO.getFlowState());
            flowApplyManager.updateByPrimaryKeySelective(flowApplyDO);
        }
    }


}
